#pragma once
#include <iostream>
#include "Mutex.hpp"
#include <queue>
#include <vector>
#include <mutex>
#include <pthread.h>
#include "mythreadPro.hpp"
#include "logMessage.hpp"
using namespace ThreadNS;
using namespace std;
const int pNum = 5;
template <class T>
class ThreadPool;
template <class T>
class ThreadData
{
public:
    string _name;
    ThreadPool<T> *_thread;

public:
    ThreadData(ThreadPool<T> *tp, string name) : _thread(tp), _name(name)
    {
    }
};
template <class T>
class ThreadPool
{
public:
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    void run()
    {
        for (auto &e : _Thread)
        {
            ThreadData<T> *td = new ThreadData<T>(this, e->ThreadName());
            e->start(HanderTask, td);
            //cout << e->ThreadName() << "start ..." << endl;
            logMessage(NORMAL,"%s start ...",e->ThreadName().c_str());

        }
    }
    static void *HanderTask(void *argv)
    {
        ThreadData<T> *tmp = static_cast<ThreadData<T> *>(argv);
        while (1)
        {
            T task;
            {
                LockGuard lockGuard(tmp->_thread->Mutex());
                while (tmp->_thread->TaskQueueIsEmpty())
                {
                    // cout<<"进入"<<endl;
                    tmp->_thread->ThreadWait();
                }
                task = tmp->_thread->Pop();
            }
            task();
        }
        delete tmp;
    }
    void push(T &in)
    {
        // 把in push进任务队列
        LockGuard lockGuard(&_mutex);
        _TaskQueue.push(in);
        pthread_cond_signal(&_cond);
    }
    T Pop()
    {
        T tmp = _TaskQueue.front();
        _TaskQueue.pop();
        return tmp;
    }
    static ThreadPool<T> *GetInstance()
    {
        if (!tp)
        {
            mx.lock();
            if (!tp)
            {
                tp = new ThreadPool<T>();
            }
            mx.unlock();
        }

        return tp;
    }
private:
    bool TaskQueueIsEmpty()
    {
        return _TaskQueue.empty();
    }
    void ThreadWait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    pthread_mutex_t *Mutex()
    {
        return &_mutex;
    }
    ThreadPool()
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < pNum; i++)
        {
            _Thread.push_back(new Thread());
        }
    }
    vector<Thread *> _Thread;
    queue<T> _TaskQueue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T> *tp;
    static mutex mx;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::tp = nullptr;
template <class T>
mutex ThreadPool<T>::mx;